#pragma once

#include "../umlmodel_global.h"

#include <memory>
#include <vector>

#include "NamedElement.h"
#include "Namespace.h"
#include "RedefinableElement.h"

using std::make_shared;
using std::shared_ptr;
using std::vector;

namespace uml {
class Classifier;
class RedefinableElement;
class State;
class StateMachine;
class Transition;
class Vertex;

/// <summary>
/// Region
/// A Region is a top-level part of a StateMachine or a composite State, that serves
/// as a container for the Vertices and Transitions of the StateMachine. A
/// StateMachine or composite State may contain multiple Regions representing
/// behaviors that may occur in parallel.
/// </summary>
class UMLMODEL_EXPORT Region : public NamedElement, public Namespace, public RedefinableElement {

public: // Constructors and destructors
    explicit Region(const QString& umlType="uml::Region");

public: // JsonSerializable override
    void fromJson(const QJsonObject& json, QStringList& errorList) override;
    void toJson(QJsonObject& json) override;

public: // Methods
    /// <summary>
    /// belongsToPSM
    /// The operation belongsToPSM () checks if the Region belongs to a
    /// ProtocolStateMachine.
    /// </summary>
    virtual bool belongsToPSM() const;

    /// <summary>
    /// containingStateMachine
    /// The operation containingStateMachine() returns the StateMachine in which this
    /// Region is defined.
    /// </summary>
    virtual shared_ptr<StateMachine> containingStateMachine() const;

    /// <summary>
    /// isConsistentWith
    /// The query isConsistentWith() specifies that a redefining Region is consistent
    /// with a redefined Region provided that the redefining Region is an extension of
    /// the Redefined region, i.e., its Vertices and Transitions conform to one of the
    /// following: (1) they are equal to corresponding elements of the redefined Region
    /// or, (2) they consistently redefine a State or Transition of the redefined
    /// region, or (3) they add new States or Transitions.
    /// </summary>
    bool isConsistentWith(shared_ptr<RedefinableElement> redefiningElement) const override;

    /// <summary>
    /// isRedefinitionContextValid
    /// The query isRedefinitionContextValid() specifies whether the redefinition
    /// contexts of a Region are properly related to the redefinition contexts of the
    /// specified Region to allow this element to redefine the other. The containing
    /// StateMachine or State of a redefining Region must Redefine the containing
    /// StateMachine or State of the redefined Region.
    /// </summary>
    bool isRedefinitionContextValid(shared_ptr<RedefinableElement> redefinedElement) const override;

public: // Properties
    /// <summary>
    /// extendedRegion getter
    /// The region of which this region is an extension.
    /// </summary>
    shared_ptr<Region> extendedRegion() const;

    /// <summary>
    /// extendedRegion setter
    /// The region of which this region is an extension.
    /// </summary>
    void setExtendedRegion(shared_ptr<Region> value);

    /// <summary>
    /// redefinitionContext getter
    /// References the Classifier in which context this element may be redefined.
    /// </summary>
    shared_ptr<Classifier> redefinitionContext() const;

    /// <summary>
    /// redefinitionContext setter
    /// References the Classifier in which context this element may be redefined.
    /// </summary>
    void setRedefinitionContext(shared_ptr<Classifier> value);

    /// <summary>
    /// state getter
    /// The State that owns the Region. If a Region is owned by a State, then it cannot
    /// also be owned by a StateMachine.
    /// </summary>
    shared_ptr<State> state() const;

    /// <summary>
    /// state setter
    /// The State that owns the Region. If a Region is owned by a State, then it cannot
    /// also be owned by a StateMachine.
    /// </summary>
    void setState(shared_ptr<State> value);

    /// <summary>
    /// stateMachine getter
    /// The StateMachine that owns the Region. If a Region is owned by a StateMachine,
    /// then it cannot also be owned by a State.
    /// </summary>
    shared_ptr<StateMachine> stateMachine() const;

    /// <summary>
    /// stateMachine setter
    /// The StateMachine that owns the Region. If a Region is owned by a StateMachine,
    /// then it cannot also be owned by a State.
    /// </summary>
    void setStateMachine(shared_ptr<StateMachine> value);

    /// <summary>
    /// subvertexs getter
    /// The set of Vertices that are owned by this Region.
    /// </summary>
    vector<shared_ptr<Vertex>>& subvertexs();

    /// <summary>
    /// transitions getter
    /// The set of Transitions owned by the Region.
    /// </summary>
    vector<shared_ptr<Transition>>& transitions();

private: // Fields
    /// <summary>
    /// extendedRegion
    /// The region of which this region is an extension.
    /// </summary>
    shared_ptr<Region> extendedRegion_;

    /// <summary>
    /// redefinitionContext
    /// References the Classifier in which context this element may be redefined.
    /// </summary>
    shared_ptr<Classifier> redefinitionContext_;

    /// <summary>
    /// state
    /// The State that owns the Region. If a Region is owned by a State, then it cannot
    /// also be owned by a StateMachine.
    /// </summary>
    shared_ptr<State> state_;

    /// <summary>
    /// stateMachine
    /// The StateMachine that owns the Region. If a Region is owned by a StateMachine,
    /// then it cannot also be owned by a State.
    /// </summary>
    shared_ptr<StateMachine> stateMachine_;

    /// <summary>
    /// subvertexs
    /// The set of Vertices that are owned by this Region.
    /// </summary>
    vector<shared_ptr<Vertex>> subvertexs_;

    /// <summary>
    /// transitions
    /// The set of Transitions owned by the Region.
    /// </summary>
    vector<shared_ptr<Transition>> transitions_;

};

} // namespace uml
